#include <iostream>
#include <string>
#include <fstream>
#include <unistd.h>
#include <vector>
#include <pwd.h>
//#include <goo/Exception>
#include "cmd.h"
#include "access_point.h"
#include "ifcfg.h"
#include "except.h"
#include "options.h"
#include "bootproto.h"


using namespace std;

string tempname;


int  main(int argc, char *argv[])
try
{
  string adaptor;
  AccessPoint *ap=0;
  AccessPoint *apbest=0;
  const int max_ap_num=20;
  vector <AccessPoint *> apvec(max_ap_num);
  bool noconnect=false;
  bool onlynet=false;
  bool onlydev=false;
  string net_name;    
  string dev_name;    
  bool dhcp=false;
  bool bootp=false;
  bool static_ip=false;

  string myname(argv[0]);
  int apnum=0;

  int uid=geteuid();
  if(uid!=0)
    {
      struct passwd *pw=getpwuid(uid);
      
      cerr << "user: " << pw->pw_name << endl;
      cerr << myname << " must be run as root. Exiting" << endl;
      return 1;
    }


  string dir="/root";
  tempname=tempnam(dir.c_str(), "iwtmp" );

  Options opt(argc, argv);
  
  noconnect = opt.has_noconnect();
  onlynet   = opt.has_network();
  onlydev   = opt.has_device();
  bootp     = opt.has_bootp();
  static_ip = opt.has_static_ip();
  dhcp      = opt.has_dhcp();
  
  if(onlynet)
    {
      net_name=opt.network_name();
      cout << "network specified - will only connect to " 
	   << net_name 
	   << endl;
    }
  if(noconnect)
    {
      cout << "noconnect specified - will not make changes" 
	   << endl;
    }
  if(onlydev)
    {
      dev_name=opt.device_name();
      cout << "device specified - will only use " 
	   << dev_name 
	   << endl;
    }

  BootProto *bp;
  if (bootp)
    {
      bp = new Bootp;
      std::cout << "BOOTP specified" << endl;
    }
  else if (static_ip)
    {
      std::string ip=opt.ip_address();
      std::cout << "Static IP specified: " << ip << endl;
      if(opt.has_gateway())
	{
	  std::string gw=opt.gateway_ip();
	  bp= new Static_ip(ip,gw);
	}
      else
	bp= new Static_ip(ip);
      
    }
  else
    {
      if(dhcp)
	std::cout << "DHCP specified" << endl;
      else
	{
	  std::cout << "no Bootproto specified: using DHCP" << endl;	
	  dhcp=true;
	}
      
      bp= new Dhcp; 
    }

  //bp->echo();
  ifstream pnw("/proc/net/wireless");
  
  string str;
  
  int adapt_ct=0;
  
  cout << "Checking /proc/net/wireless..." << endl;
  int pnwline=0;
  while (!pnw.eof() && pnw.good() )
    {	  
      getline(pnw,  str);
      if(pnw.eof() || pnw.bad())
	break;
      
      //cout << "pwn: " <<  str << endl;
      if(pnwline>1 && str.length() >0)
	{
	  if(str.find("lan")!=string::npos)
	    {
	      char buff[132];
	      strncpy(buff,str.c_str(),132);
	      char *ptr=strtok(buff,":");
	      if(!onlydev)
		{
		  if(adapt_ct==0)
		    adaptor=ptr+1; // proc/net/wireless adds a 
		                   // space b4 adap name
		  cout << "Founnd Wireless Adapter: " << ptr << endl;
		  adapt_ct++;
		}
	      else
		{
		  if(!dev_name.compare(ptr+1))
		    {		      	
		      adaptor=ptr+1; // proc/net/wireless adds a 
		                     // space b4 adap name
		      cout << "Founnd Wireless Adapter: " << adaptor << endl;
		      adapt_ct++;
		    }
		}
	    }
	} 
      pnwline++;	  
    }
  
  if(adapt_ct <1)
    {
      cout << "No Wireless Device Installed.  Exiting" << endl;
      return 0;
    }
  
  cout << "Found " << adapt_ct << " Wireless Adaptor(s)" << endl;
  cout << "Using " << adaptor << endl;

  
  Cmd link_up("/sbin/ip link set dev",adaptor,"up");
  Cmd link_down("/sbin/ip link set dev",adaptor,"down");

  // bring link up to enable scan
  //link_up.echo();
  link_up.exec();

  // scan for networks
  Cmd cmd("/sbin/iwlist ", adaptor, " scanning > ", tempname, " 2>&1");
  cmd.exec();

  // bring link down so when se connect device won't be busy
  //link_down.echo();
  if(!noconnect)
    link_down.exec();
  
  ifstream aplist(tempname.c_str() );
  
  
  //  cout << endl << "IWLIST SCAN" << endl;
  
  if(aplist.bad())
    {
      cout << "could not read scan" << endl;
      return 0;
    }
  
  while (!aplist.eof() && !aplist.bad())
    {
      string str;
      getline( aplist, str);  
      //  cout  << "aplist: " << str << endl;
      if(str.find("Address:")!=string::npos)
	{
	  // found access point
	  if(ap!=0)
	    {
	      cout << "Access Point #" << apnum++ << endl;
	      ap->print_line();
	      if(apbest==0 
		 || (ap->get_quality() > apbest->get_quality()))
		{
		  if(onlynet)
		    {
		      if(!net_name.compare(ap->get_essid()) )
			{
			  apbest=ap;
			}
		    }
		  else if(!ap->is_secure())
		    apbest=ap;
		}
	    }
	  ap=new AccessPoint;
	  apvec.push_back(ap);
	}
      if(ap!=0)
	ap->parse_scan_line(str);      
    }
  
  unlink(tempname.c_str());
  
  if(ap!=0)
    {
      cout << "Access Point #" << apnum << endl;
      ap->print_line();
	  if(!onlynet)
	    {
	      apnum++;
	    }
      if(apbest==0 
	 || (ap->get_quality() > apbest->get_quality()))
	{
	  if(onlynet)
	    {

	      if(!net_name.compare(ap->get_essid()) )
		{
		  apbest=ap;
		  apnum++;
		}
	    }
	  else if(!ap->is_secure())
	    apbest=ap;
	}
    }
  

  if(apnum>0)
    {
      // this should be configurable
      string fname("/etc/sysconfig/network-scripts/ifcfg-");
      fname+=adaptor;

      cout << endl << "Found " << apnum << ": Access Point(s) " << endl;
      if(apbest!=0)
	{
	  if(!noconnect)
	    {
	      cout << "Connecting to " << apbest->get_essid() << endl;
	      if(apbest->connect(adaptor))
		{
		  
		  IfCfg ifcfg(fname,adaptor,apbest, bp);
		  if(!ifcfg.out())
		    {
		  cout << "Success!" << endl;
		  // let user restart network manually
		  
		  std::cout << "You need to restart your network." 
			    << std::endl
			    << "a typical command to do this is:" 
			    << std::endl
			    << "    /etc/init.d/network restart" 
			    << std::endl;
		  //Cmd restart("/etc/init.d/network restart");
		  //restart.echo();	  
		  // restart.exec();
		  
		  // Cmd ifconfig("ifconfig",adaptor); 
		    }
		  else
		    {
		  cout << "cfg file could not be updated" << endl;
		  cout << endl;
		    }
		  
		}
	      else
		{
		  cout << "Failed." << endl;
		}
	    }
	  else
	    {
	      // no Connect specified
	      IfCfg ifcfg(fname,adaptor,apbest, bp);
	      ifcfg.echo();
	    }	  
	}
      else
	{
	  if(onlynet)
	      cout << "Specified network found but secure" << endl;
	  else
	      cout << "NO non-secure networks found" << endl;
	}
    }
  else
    {
      if(onlynet)
	cout << "Specified network not found" << endl;
      else
	cout << "No  networks found" << endl;
    }

  // bring up link in case it what up to begin with
  // link_up.echo();
  link_up.exec();

  return 0;
}
 catch(FatalError &e)
   {
     e.print();
     return 1;
   }
 catch(Warning& e)
   {
     e.print();
     return 0;
   }
 catch(NoError& e)
   {
     return 0;
   }
